<?php
namespace App\GameService\games;

use App\Common\GameCommon;
use App\Utility\BaseEnum;
use App\Common\AuthCommon;
use Swoole\Timer;
use App\Utility\RedisTools;
use App\Enum\MahjEnum;
use App\Common\BaseComm;
use App\Enum\CardEnum;
use App\Model\GameType;
use App\Enum\PorkerEnum;
use App\Enum\SysEnum;
use App\Utility\DBTools;

/**
 * 德洲扑克游戏
 *
 * @author Administrator
 */
class PlayDZPoker extends BasePlay
{
    // 初始化
    public function __construct() {
        //TODO 配置时间:时间问题
        $this-> gtimeConfig = array(
            "firstcard_long" => 1,      //初始化时长(发玩家手牌)
            "everybet_long" => 10,      //第个玩家等待下注时长
            "waitdeal_long" => 5,       //发牌完成完成，等待结算时长
        );
    }
    
    /**
     *  TODO 扑克游戏入口；
     *  必须实现这个方法；
     *  游戏开始逻辑
     *  发牌一般分为5个步骤，分别为：
     *  Perflop—先下大小盲注，然后给每个玩家发2张底牌，大盲注后面第一个玩家选择跟注、加注或者盖牌放弃，按照顺时针方向，其他玩家依次表态，大盲注玩家最后表态，如果玩家有加注情况，前面已经跟注的玩家需要再次表态甚至多次表态。
     *  Flop—同时发三张公牌，由小盲注开始（如果小盲注已盖牌，由后面最近的玩家开始，以此类推），按照顺时针方向依次表态，玩家可以选择下注、加注、或者盖牌放弃。
     *  Turn—发第4张牌，由小盲注开始，按照顺时针方向依次表态。
     *  River—发第五张牌，由小盲注开始，按照顺时针方向依次表态，玩家可以选择下注、加注、或者盖牌放弃。
     *  比牌—经过前面4轮发牌和下注，剩余的玩家开始亮牌比大小，成牌最大的玩家赢取池底。
     */
    public function asycStartGame($gameNo, $gameRId = FALSE, $fjInfo = FALSE, &$commonLoopTimer = 0)
    {
        $gameId = isset($fjInfo['gameId']) ? intval($fjInfo['gameId']) : 0;
        $maxBindBets = isset($fjInfo['everyPoints']) ? floatval($fjInfo['everyPoints']) : 0;    //大盲注金额
        $useCards = GameCommon::createCardList($gameId, $gameNo, false); // 启动发牌 ： XYM_0X19；
        BaseEnum::Logger("游戏开始生成牌:Gameporker-(PlayDZPoker)-{$gameId} 游戏[{$gameNo}]牌值：---->>>" . json_encode($useCards), 'user-login'); // 所有玩家FD
        if(!$useCards)return FALSE;
        
        $betLong = $this->getConfigTimeLong('everybet_long') ?? 10;
        $Long = $this->getConfigTimeLong('firstcard_long') ?? 2;
        //TODO : 每个玩家发2张底牌
        Timer::after($Long * 1000, function() use($gameNo,$useCards,$maxBindBets,$betLong){
            $useCards = !empty($useCards) ? array_column($useCards, "cards",'seatNo') : FALSE;
            $fjData = BaseComm::distMemoryRooms($gameNo, FALSE);                                // 内存数据；
            if(!$fjData || !$useCards) return FALSE;
            $deskAllMoney = $fjData["deskMoney"] ?? 0;                                          //桌面分数
            $fjSta = isset($fjData['fjStatus']) ? intval($fjData['fjStatus']) : 0;
            $gamePlays = isset($fjData['lists']) ? $fjData['lists'] : FALSE;                    // 玩家列表；
            $lastSitIndex = isset($fjData["lastSiteNo"]) ? intval($fjData["lastSiteNo"]) : 0 ;
            $playFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false;  // 座位列表
            BaseEnum::Logger('取内存数据:Games-(PlayDZPoker)-[asycStartGame]--->>>' . json_encode($fjData), 'user-login');
            foreach ($playFds as $seid => $fdVal){
                $playcard = isset($useCards[$seid]) ? $useCards[$seid] : FALSE ;
                if(!empty($playcard)){
                    $pushdata = array('m'=>BaseEnum::XYM_0X17,"data"=> ["seatNo"=>$seid,'cards'=>$playcard,"other_card" => 1,"deskMoney"=> floatval($deskAllMoney)]);
                    AuthCommon::pushFrontWeb($fdVal,json_encode($pushdata)); //推送发牌成功
                }
            }
            
            //TODO 第一轮表态：跟注，每个玩家跟注或者加注
            BaseEnum::Logger("第一轮表态：Games-(PlayDZPoker)->  从玩家[siteNo={$lastSitIndex}]开始---->>>" . json_encode($playFds), 'user-login'); // 所有玩家FD
            $startdata = array('m'=>BaseEnum::XYM_0X63,"data"=> ["seatNo"=>-1,'nextSiteNo'=> 3,"nextBet" => $maxBindBets,"deskMoney"=> floatval($deskAllMoney),"nextWaitTime" => $betLong,"maxLenScore"=> $maxBindBets]);
            AuthCommon::pushFrontWeb($playFds , json_encode($startdata)); //推送发牌成功
            
            //TODO 进入下一步
            $next_seaid = $lastSitIndex + 1;
            $this ->waitPlayerHander($gameNo, $playFds,$fjSta,$next_seaid);
        });
    }
    
    
    /**
     * TODO 检测玩家已经弃牌，以及是否可以结束当前轮所有用户操作
     * @param string $gameNo
     * @param array $fjDetail
     */
    protected function checkGameReStart($gameNo,$gamePlays = FALSE,$gameLun,&$gameOverNum = 0, &$lastRes = FALSE) {
        $allNum = sizeof($gamePlays);   //总人数
        $lastNoLossUser = FALSE;        //最后一个没有弃牌用户
        $newUserBet = [];
        BaseEnum::Logger("第{$gameLun}轮统计：内存数据 => " . json_encode($gamePlays), 'user-login'); // 所有玩家FD
        foreach ($gamePlays as $setin => $oneplayer){
            $isOver = isset($oneplayer["play_hand"]) ? intval($oneplayer["play_hand"]) : -1;
            $curLun = isset($oneplayer["play_lun"]) ? intval($oneplayer["play_lun"]) : 0;   //计轮数
            if (isset($isOver) && $isOver === 0) {          //弃牌数
                $gameOverNum += 1;
            }else if(!empty($oneplayer) && $isOver !== 0){  //弃牌
                $lastNoLossUser = $oneplayer;
                if($curLun > 0 && $curLun === $gameLun){    //TODO 条件1：轮号相同( 特殊情况下：当$gameLun = 1,玩家也要统计在内时 )
                    $newUserBet[$setin] = isset($oneplayer["play_lunmoney"]) ? floatval($oneplayer["play_lunmoney"]) : 0;
                }
            }
        }
        BaseEnum::Logger("第{$gameLun}轮统计：弃牌人数{$gameOverNum}个 [Total={$allNum}]--这轮(未弃牌)玩家下注情况 => " . json_encode($newUserBet), 'user-login'); // 所有玩家FD
        //TODO 弃牌就就直接结束 最后一玩家赢 ；
        if($gameOverNum > 0 && $gameOverNum + 1 === $allNum  && !empty($lastNoLossUser)){
            $lastRes = $lastNoLossUser;
            return TRUE;
        }
        $lastRes = $newUserBet ;        //没弃牌就统计当前局的数据；
        return FALSE;
    }
    
    
    //TODO 异步操作（可以提前中断的功能）
    protected function asycLoading($sleepTime,$gameNo,$callBackFun = null) {
        //倒计时的内容放在内存变量中
        PlayHelp::getInstance()->setLoopTim($gameNo,$sleepTime);
        //TODO 启用定时器；推送倒计时给前端
        $this->tempLoadTimer = Timer::tick(1000, function() use ($gameNo,$callBackFun, $sleepTime){
            $myVal = PlayHelp::getInstance()->getLoopTim($gameNo);
            $myVal = $myVal - 1;
            PlayHelp::getInstance()->setLoopTim($gameNo,$myVal);                    // 保存修改后的值
            $loopTimerStop = PlayHelp::getInstance()->getCommTimerStop($gameNo);    //停掉定时器
            if (intval($myVal) <= 0 || $loopTimerStop === true) {                   //特殊情况中断倒计时数据；
                Timer::clear($this->tempLoadTimer);
                $this->tempLoadTimer = null;
                PlayHelp::getInstance()->setCommTimerStop($gameNo,FALSE);           //unset(Games::$gameCommonTimer[$gameNo]);    //清空数据
                BaseEnum::Logger("临时等待定时器工作结束：(clear)-倒计时结束执行功能： [tempLoadTimer]--->>>>loop={$loopTimerStop}----->". $gameNo, 'user-login');
                if($callBackFun !== FALSE){ 
                    @call_user_func($callBackFun);                                  //回调方案
                }
            }
        });
    }
    
    /**
     * TODO 玩家表态等待10时间；
     * @param string $gameNo 局号
     * @param array $playFds 玩家FD
     * @param number $fjStatus 状态
     * @param boolean $lastSitIndex 最后玩家ID值
     */
    protected function waitPlayerHander($gameNo,$playFds,$fjStatus=0,$lastSitIndex = FALSE , $gameLun = 1) {
        $betLong = $this->getConfigTimeLong('everybet_long') ?? 10; //玩家下注等待时长
        $num_total  = !empty($playFds) ? sizeof($playFds) : 0 ;
        if($num_total > 0 && $lastSitIndex > 0 && $lastSitIndex >= $num_total )  $lastSitIndex = 0; //下一位玩家座位号；
        $Parms = ["gameNo" => $gameNo, "clientIds" => $playFds,"gameLun"=> $gameLun , "status" => $fjStatus,"waitSiteNo"=> $lastSitIndex];
        BaseEnum::Logger("Wait玩家操作：(asycTimeStart)->  玩家[siteNo={$lastSitIndex} =>" . json_encode($Parms), 'user-login'); // 所有玩家FD
        
        //TODO 表态定时器等待 ====倒计时10秒钟
        $this->asycLoading($betLong,$gameNo,function () use ($gameNo, $playFds,$fjStatus,$lastSitIndex,$num_total,$gameLun,$betLong) {
            usleep(50);
            //TODO： 第一轮表态：当前玩家没有表态自动表态            
            $fjDetail = BaseComm::distMemoryRooms($gameNo,FALSE);
            $gameRId = isset($fjDetail["grid"]) ? intval($fjDetail["grid"]) : 0;            //房间 ID
            $deskMoney = isset($fjDetail["deskMoney"]) ? floatval($fjDetail["deskMoney"]) : 1;
            //TODO　最小跟注金额(根据上一个玩家加注数据来决定)
            $pushPlayer = ["seatNo"=>$lastSitIndex,'type'=> -1,"gLun" => $gameLun,"deskMoney" => $deskMoney,"money" => 0,"nextSiteNo" => -1,'nextBet' => 0,"nextWaitTime"=>$betLong,"maxLenScore"=> 0];
            $gamePlays = isset($fjDetail['lists']) ? $fjDetail['lists'] : FALSE;                        // 玩家列表；
            $currUser = isset($gamePlays[$lastSitIndex]) ? $gamePlays[$lastSitIndex] : FALSE ;          //玩家是否表态
            $currLunIndex = isset($currUser['play_lun']) ? intval($currUser['play_lun']) : 0;
            $currHandIndex = isset($currUser['play_hand']) ? intval($currUser['play_hand']) : -1 ;
            $curLunMoney = isset($currUser['play_lunmoney']) ? floatval($currUser['play_lunmoney']) : 0 ;//当前这轮原有的MONEY
            //TODO 统计本局跟注金额(两个条件：1、当前轮编号都一致，2、每个玩家跟注金额都一样)
            $LocalUserBet = [];
            foreach ($gamePlays as $onep){
                $se_vid = isset($onep['seatNo']) ? intval($onep['seatNo']) : 0 ;
                $userLun = isset($onep['play_lun']) ? intval($onep['play_lun']) : 0 ;
                $ifLunOk = ($userLun>0 && $gameLun>0 && $userLun==$gameLun) ? TRUE :FALSE;  //同一轮
                
                //TODO 取最高下注数 ( 特殊情况下：当 $gameLun = 1,玩家也要统计在内时)
                if($ifLunOk == TRUE && isset($onep['play_lunmoney']) && $se_vid >= 0){
                    $LocalUserBet[$se_vid] = floatval($onep['play_lunmoney']);              //取本轮要跟注的金额；
                }else if($userLun == 0 &&  $gameLun == 1){
                    $LocalUserBet[$se_vid] = floatval($onep['play_lunmoney']);              //刚开始把大小盲注都加进去；
                }
            }
            $maxBetPrice = !empty($LocalUserBet) ? floatval(max($LocalUserBet)) : 0 ;
            BaseEnum::Logger("检查玩家表态数据：第{$currLunIndex}轮---需要最大筹码：{$maxBetPrice}] 查询玩家-->" . json_encode($LocalUserBet), 'user-login'); // 所有玩家FD
            $lastUserHand = $currHandIndex;
            
            //TODO 已弃牌不参与自动处理
            if ($currHandIndex !== CardEnum::DZPK_TYPE_0) {
                
                //TODO  是否已经表态过(同时满足两个条件并且达到最大金额)
                if ($currLunIndex && $currLunIndex === $gameLun  && $curLunMoney === $maxBetPrice ) {       //满足(过牌)条件
                    $pushPlayer["money"] = $curLunMoney;                                                    //玩家表态的金额
                    BaseEnum::Logger("玩家表态查询：第{$currLunIndex}轮---已表态：{$currHandIndex}，分数 ：{$curLunMoney}]，不执行存储内存数据 -->" . json_encode($currUser), 'user-login'); // 所有玩家FD
                }else{
                    //TODO 玩家未操作[未表态]  ====> 交给系统处理：弃牌or跟牌
                    $currUser["play_lun"] = $gameLun;
                    if($currLunIndex !== $gameLun){         //第一次进来
                        $currHandIndex = -1;
                        $currUser['play_hand'] = -1;
                        $currUser['play_lunmoney'] = 0;
                        if($gameLun === 1 && isset($currUser['blind_money']) && floatval($currUser['blind_money']) > 0){             //第一轮时的钱为
                            $currUser['play_lunmoney'] = floatval($currUser['blind_money']);
                        }
                    }
                    //TODO 什么情况应该弃牌(如果本局内没有主动加注或所有玩家都一样时，需计算所有人在本局内的数据是否都一样)
                    if($currHandIndex > 1){
                        $currUser['play_hand'] = $currHandIndex;                    //保持原来的标识不变
                    }else{
                        $currUser['play_hand'] = CardEnum::DZPK_TYPE_0;             //默认弃牌（当位置不是大小盲注的玩家）
                        if($maxBetPrice <= 0 || ($maxBetPrice > 0 && $curLunMoney > 0 && $curLunMoney == $maxBetPrice)){  //达到这一轮的值就可以默认过牌
                            $currUser['play_hand'] = CardEnum::DZPK_TYPE_1;         //可以默认过牌
                        }
                    }
                    $lastUserHand = $currUser["play_hand"];                         //最后的操作结果
                    $gamePlays[$lastSitIndex] = $currUser;
                    $fjDetail["lists"] = $gamePlays;
                    BaseEnum::Logger("玩家表态查询：第{$currLunIndex}轮--- !!!!未表态!!!! => 系统自动转：{$currHandIndex}，可能下注分 ：{$curLunMoney}] -->" . json_encode($currUser), 'user-login'); // 所有玩家FD
                }
            }else{
                $pushPlayer["money"] = $curLunMoney; //已弃牌也包含有money
            }
            
            //TODO 当前位置弃牌要推送出去，并且带上下一位玩家跟牌金额和最高加注额
            $fjDetail["fjStatus"]   = 1;
            $fjDetail["lastSiteNo"] = $lastSitIndex;            //记录最后一个玩家位索引
            $fjDetail["playTimes"]  = $gameLun ;                //记录轮数
            BaseComm::distMemoryRooms($gameNo,TRUE,$fjDetail);  //更新表态数据到内存中处理（用户自己操作，和系统默认弃牌处理 ）；
            $pushPlayer['type'] = $lastUserHand;
            BaseEnum::Logger("表态完成：(waitPlayerHander)->  玩家[siteNo={$lastSitIndex}__play---->{$lastUserHand},最大筹码：{$maxBetPrice}] 操作表态 [ SUCCESS ] !!=>" . json_encode($currUser), 'user-login'); // 所有玩家FD
            
            //TODO 检查操作（执行下一步）
            
            $gameOver = 0;
            $lastRes = FALSE ;
            
            //TODO 检测所有玩家(  1、玩家弃牌，最后一个人赢结束 ， 2、没结束 继续后面的 每轮下注)            
            $checkJG = $this -> checkGameReStart($gameNo,$gamePlays,$gameLun,$gameOver,$lastRes);
            if ($checkJG === TRUE) {
                $userRes = [];
                
                //TODO 游戏弃牌提前结束
                $pushPlayer['nextSiteNo'] = -1000; 
                $pushdata = array('m'=>BaseEnum::XYM_0X63,"data"=> $pushPlayer);
                AuthCommon::pushFrontWeb($playFds,json_encode($pushdata));  
                
                BaseEnum::Logger("第{$gameLun}轮弃牌提前结束：(waitPlayerHander)->  弃牌人数{$gameOver}个 [Total={$num_total}]--获胜玩家=>" . json_encode($lastRes), 'user-login'); // 所有玩家FD
                $fjDetail = BaseComm::distMemoryRooms($gameNo,FALSE);
                BaseEnum::Logger("内存数据 =>" . json_encode($fjDetail), 'user-login');          // 所有玩家FD
                $allUserLists = isset($fjDetail['lists']) ? $fjDetail['lists'] : FALSE;
                $deskAll = isset($fjDetail["deskMoney"]) ? floatval($fjDetail["deskMoney"]) : 0;
                
                
                $notGiveupIds = [];
                
                //TODO 比牌前赢的钱都是当前这个桌面上的所有钱 (桌面上多少钱)；
                foreach ($allUserLists as $settno => $userdet){
                    $oneUid = isset($userdet['uid']) ? intval($userdet['uid']) :0 ;
                    $oneHand = isset($userdet['play_hand']) ? intval($userdet['play_hand']) : -1 ;
                    $totalMoney = isset($userdet['total_money']) ? floatval($userdet['total_money']) :0 ; //玩家自己下注金额； 
                    $xjMoney = $xjBetMoney = $water2 = 0;
                    if($oneUid <= 0) continue;
                    if($oneHand === 0){                                                     //弃牌就是默认下注的人的钱都是输掉的
                        $xjMoney = 0 - $totalMoney; 
                        $xjBetMoney = ($xjMoney < 0) ? abs($xjMoney) : 0;
                    }else {
                        array_push($notGiveupIds,$oneUid);
                        $xjMoney = bcsub($deskAll,$totalMoney,3);                           //第一个玩家赢的玩家拿走所有桌面上的钱
                        $water2 = bcmul(BaseComm::getSetWaterDott(), $xjMoney ,3) ;         //抽水的钱
                        $xjBetMoney = bcsub($xjMoney , $water2 , 3) ;                       //有效下注
                    }
                    // 结算金额的钱值
                    $userRes[$settno] = array(
                        "uid" => $oneUid,
                        "seatNo" => $settno,
                        "money"  => floatval($xjMoney),         //盈亏值
                        "eachprice" => floatval($xjBetMoney),   //有效下注(正数)
                        "cellScore" =>  $totalMoney,                          //TODO 有效下注（取所有位置的下注总和）下多少分
                        "allBetScore" => $totalMoney,                         //TODO 所有位下注总分
                        "lastPoints"=>  floatval($xjMoney),             //TODO 实际输赢（除去水钱）
                        "level"  => 1 ,
                        "card_mutle" => 1,
                        "water"  =>   floatval($water2),
                    );
                }
                //处理完
                BaseEnum::Logger("弃牌结算：所有玩家盈亏状态 =>" . json_encode($userRes), 'user-login'); // 所有玩家FD
                
                //结算订单操作
                $this -> dealGameUserOrder($gameRId,$gameNo,$userRes,$allUserLists,$notGiveupIds);
                return FALSE;
            }else{
                //TODO 继续进入下一个玩家表态
                //$next_seaid = $lastSitIndex + 1; 
                $next_bet_money = 0;    //下一位跟注金额
                //TODO 本轮是否可以结束
                $currentLunIsFinish = FALSE; 
                //继续条件2：下注是否达到当前局所有玩家都相同下注额
                $alreayNum = !empty($lastRes) ? sizeof($lastRes)  : 0;
                $maxBetValue = !empty($lastRes) ? max($lastRes)  : 0 ;      //最高下注金额
                $seatBets = !empty($lastRes) ? array_unique($lastRes)  : FALSE;
                
                //TODO 所有玩家处理完(都处于同一局，并且所有玩家的下注金额都一样或都没有下注)
                if(!empty($seatBets) && sizeof($seatBets) == 1  && $alreayNum + $gameOver >= $num_total){  
                    $currentLunIsFinish = TRUE;
                }
                //TODO 查询下一位玩家
                $getNextId = self::selectNextPlayer($lastSitIndex,$gameLun,$maxBetPrice,$gamePlays,$currentLunIsFinish,$next_bet_money);
                $pushPlayer['maxLenScore'] = $maxBetPrice > 0 ? $maxBetPrice: 0; //本轮最高下注额
                
                //TODO 所有玩家处理完(都处于同一局，并且所有玩家的下注金额都一样或都没有下注)
                if($currentLunIsFinish === TRUE){   
                    
                    //TODO 下一轮开始也要发送出去
                    $pushPlayer['nextSiteNo'] = $getNextId;
                    $pushPlayer['nextBet'] = 0;
                    $pushPlayer['nextWaitTime'] = 12; //进入下一局(都是过牌操作，加时2秒)
                    $pushdata = array('m'=>BaseEnum::XYM_0X63,"data"=> $pushPlayer);
                    AuthCommon::pushFrontWeb($playFds,json_encode($pushdata));  
                    
                    //TODO 满足下一轮操作；（发公共牌再下注）
                    $nextLun = $gameLun + 1;
                    BaseEnum::Logger("第{$gameLun}轮[ALL--表态--FINISH ]表态完成：(waitPlayerHander)->  进入第{$nextLun}轮 [lastSiteNo={$lastSitIndex}]--SUCCESS-->>>" . json_encode($gamePlays), 'user-login'); // 所有玩家FD
                    
                    $this -> NextSecondGame($gameRId,$gameNo,$getNextId,$nextLun);
                    return FALSE;
                }
                
                
                
                //TODO 1、每个位都有下注；但有玩家加注，前面的玩家要再次跟注
               /*  if(!empty($seatBets) && sizeof($seatBets) > 1  && $alreayNum + $gameOver >= $num_total && $maxBetValue > 0){
                    foreach ($seatBets as $seatid => $bet){
                        if($maxBetValue > $bet){  
                            $next_seaid = $seatid ; 
                            $next_bet_money = $maxBetValue - $bet;  //取当前这个位置的玩家
                            break ;
                        }    
                    }
                    BaseEnum::Logger("第{$gameLun}轮[seatNo={$lastSitIndex}]已完成： 因玩家加注，位置 [lastSiteNo={$next_seaid}]--需要再次加注 ====>" . json_encode($seatBets), 'user-login'); // 所有玩家FD
                }
                //TODO 2、还未结束寻找下一玩家进行下注
                else {
                    $next_bet_money = $maxBetValue;
                    $next_status = TRUE;
                    do{
                        if($num_total > 0 && $next_seaid > 0 && $next_seaid >= $num_total )  $next_seaid = 0;
                        //判断玩家是否弃牌 ===> 跳过这个玩家
                        $nextUser = isset($gamePlays[$next_seaid]) ? $gamePlays[$next_seaid] : FALSE ;
                        BaseEnum::Logger("NEXT-玩家表态：(waitPlayerHander)->  玩家[siteNo={$next_seaid}]信息---->>>" . json_encode($nextUser), 'user-login'); // 所有玩家FD
                        //跳过弃牌位置
                        if(isset($nextUser["play_hand"]) && intval($nextUser["play_hand"]) == 0){
                            $next_seaid ++ ;
                            $next_status = FALSE;
                            BaseEnum::Logger("提示已弃牌：(Player 已弃牌)->  下一位[siteNo={$next_seaid}]", 'user-login');   // 所有玩家FD
                        }else{
                            $next_status = TRUE;
                        }
                    }while($next_status === FALSE);
                } */
                
                //TODO 推送当前玩家的  操作数据
                $pushPlayer['nextSiteNo'] = $getNextId;
                $pushPlayer['nextBet'] = $next_bet_money;                           //下一位玩家要跟注多少钱
                $pushdata = array('m'=>BaseEnum::XYM_0X63,"data"=> $pushPlayer);
                AuthCommon::pushFrontWeb($playFds,json_encode($pushdata));          //推上一玩家操作，和下一玩家座位号
                
                @sleep(2); //TODO  下一位玩家开始表态
                $this ->waitPlayerHander($gameNo, $playFds,$fjStatus,$getNextId , $gameLun);
            }
        });
    }
    
    
    /**
     * TODO 查找还未满足条件的下一位玩家； 
     * @param number $playNextBetMoney 是否满足进入下一轮True
     * @return number
     */
    protected static  function selectNextPlayer($lastSeatNo,$currLun = 1,$maxPrice = 0 , $gamePlays = FALSE,$IsFinish = FALSE,&$playNextBetMoney = 0){
        $next_status = TRUE;
        $finishNum = 0;
        $num_total = !empty($gamePlays) ? sizeof($gamePlays) : 0 ;
        //$playNextBetMoney = 0;    //下一位跟注金额
        $next_seaid = $lastSeatNo + 1;
        BaseEnum::Logger("查找NEXT玩家[old_No={$lastSeatNo}]：( maxBet={$maxPrice} )->  下一位 ==> [siteNo={$next_seaid}]", 'user-login');
        do{
            //TODO 继续进入下一个玩家表态
            if($num_total > 0 && $next_seaid > 0 && $next_seaid >= $num_total )  $next_seaid = 0;
            
            //TODO 判断玩家是否弃牌 ===> 跳过这个玩家
            $nextUser = isset($gamePlays[$next_seaid]) ? $gamePlays[$next_seaid] : FALSE;
            $pLun = $nextUser["play_lun"] ?? 0;
            $ptype = $nextUser["play_hand"] ?? -1;
            $pLunPrice = $nextUser["play_lunmoney"] ?? 0;
            $isLunFinish = ($pLun == $currLun && $maxPrice == $pLunPrice) ? TRUE : FALSE;
            
            //TODO 当前轮已结束；下一轮判断
            if ($IsFinish === TRUE) {
                $LunNext = $currLun + 1;
                $isLunFinish = ($pLun == $LunNext && $maxPrice == $pLunPrice) ? TRUE : FALSE;
            }
            if ($ptype === 0  || $isLunFinish === TRUE) {  //找不满足条件的
                $next_status = FALSE;
                $finishNum  ++ ;
                $nextSid = $next_seaid + 1;
                BaseEnum::Logger("NEXT玩家[No={$next_seaid}]：(当前这轮已完成。 playHand={$ptype} )->  GoOn 下一位 ==> [siteNo={$nextSid}]", 'user-login');   // 所有玩家FD
                $next_seaid = $nextSid;
                if($finishNum >= $num_total) {
                    $next_status = TRUE;
                    break;
                }
            }else{
                $next_status = TRUE;
                //TODO 寻找的这位满足条件：money计算
                $ifPok = ($pLun == 0 || ($pLun > 0 && $pLun == $currLun))  ? TRUE : FALSE ;
                if ($ifPok === TRUE && $maxPrice > 0) {
                    //TODO 同一轮补差值
                    $playNextBetMoney = $maxPrice - $pLunPrice;
                }else{
                    $playNextBetMoney = $maxPrice;
                }
                BaseEnum::Logger("NEXT-玩家[siteNo={$next_seaid}] 在第{$currLun}轮未下注（需要补跟注分：{$playNextBetMoney},总分:{$maxPrice}），请等待-->>>" . json_encode($nextUser), 'user-login'); // 所有玩家FD
            }
        }while($next_status === FALSE);
        
        
        //TODO 返回数据处理
        return $next_seaid;
    }
        
    

    /**
     *  T 进入下一步处理事件
     */
    public function doNextPlayBets($loginFd, $gameNo, $fjDetail = FALSE, $getUix = FALSE)
    {
        // 动画处理完触发；只能调用一次；触发动画倒计时；
        $fjSta = isset($fjDetail['fjStatus']) ? intval($fjDetail['fjStatus']) : 0;
        $gamePlays = isset($fjDetail['lists']) ? $fjDetail['lists'] : FALSE; // 玩家列表；
        $playerFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false; // 座位列表
        $Parms = [
            "gameNo" => $gameNo,
            "clientIds" => $playerFds,
            "status" => $fjSta
        ];
        $zjUserInfo = FALSE;
        if (! empty($gamePlays) && sizeof($gamePlays) >= 2) { // 查找庄家信息；
            foreach ($gamePlays as $oneuser) {
                if (isset($oneuser["uid"]) && intval($oneuser["uid"]) > 0 && isset($oneuser["mainflag"]) && intval($oneuser["mainflag"]) === 1) { // 庄家 mainflag = 1
                                                                                                                                                  // 庄家的倍数
                    $zjUserInfo = array(
                        "uid" => $oneuser["uid"],
                        "seatNo" => @$oneuser["seatNo"],
                        "bet_mutle" => isset($oneuser['mutdotts']) ? intval($oneuser['mutdotts']) : 0,
                        "main_flag" => 1 // 标识为庄主;
                    );
                    break;
                }
            }
        }
        // 标识为庄主;
        if (! $zjUserInfo || ! isset($zjUserInfo['uid']) || intval($zjUserInfo['uid']) <= 0)
            return FALSE;

        $this->asycTimeStart(2, $gameNo, $Parms, function () use ($gameNo, $gamePlays, $playerFds, $fjDetail, $zjUserInfo) { 
        });
    }

    /**
     * TODO 恢复游戏数据；  处理以下几张情况
     * 1、抢庄中---谁庄过庄（标识出来），
     * 2、下注中(谁是庄家标识出来，)
     * 3、结算中(庄家，下注倍数，当前玩家牌值内容)
     *
          * 附状态值：0 => '匹配', 1 => '抢庄', 2 => '下注', 3 => '发牌', 4 => '拼牌', 5 => '结算',
     * @param int $gameStatus
     * @param array $gamePlays
     */
    public static function reBackData($loginUid, $gameStatus, $gameNo = FALSE, $gamePlays = FALSE)
    {
        if (! $loginUid || ! $gamePlays || ! $gameNo)
            return false;
        $redisobj = new RedisTools();
        $redisobj->select(0);
        $palyUser = $gamePlays;
        foreach ($palyUser as & $oneus) {
            unset($oneus['fd']);
            unset($oneus['agentId']);
            unset($oneus['betmoney']);
        }
        // 匹配成功 开始抢庄 ===> 谁有抢庄
        if ($gameStatus === CardEnum::GAME_STEP_0) {
            $rediskey = SysEnum::ONLINE_BDATA_KEY . "_MUT"; // 查询下注数据；
            $betdata = $redisobj->hGet($rediskey, $gameNo);
            $betArray = ! empty($betdata) ? json_decode($betdata, TRUE) : FALSE;
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = '玩家抢庄';
            }
        } // 抢庄完成 开始下注 ===> 标出谁是庄家,闲家下注倍数；
        else if ($gameStatus === CardEnum::GAME_STEP_1) {
            $rediskey = SysEnum::ONLINE_BDATA_KEY . "_MUT"; // 查询下注数据；
            $betdata = $redisobj->hGet($rediskey, $gameNo);
            $betArray = ! empty($betdata) ? json_decode($betdata, TRUE) : FALSE;
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = '闲家下注';
                if (isset($oneuser['mainflag']) && intval($oneuser['mainflag']) == 1) { // 定庄：uid,
                    $palyUser[$sid]['text'] = '庄';
                    $palyUser[$sid]['pstatus'] = '等待闲家下注';
                } else {
                    $palyUser[$sid]['text'] = '闲';
                    $palyUser[$sid]['mutdotts'] = isset($betArray[$sid]) ? intval($betArray[$sid]) : 0; // 闲家下注倍数
                    $palyUser[$sid]['max_mutle'] = 15; // 最大下注倍数；
                }
            }
        } // 下注完成 开始发牌 拼牌 ===> 开始发牌（显示下注倍数）
        else if (in_array($gameStatus, [
            CardEnum::GAME_STEP_2,
            CardEnum::GAME_STEP_3
        ], true)) {
            $cards = BaseComm::distMemoryCards($gameNo,FALSE); // 全局变量获取手牌数据（座位号seatNo=> [11,23,233]）
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = ($gameStatus == 3) ? "拼牌中" : '发牌中';
                $palyUser[$sid]['ifcards'] = 1; // 已发牌
                $palyUser[$sid]['cards'] = false; // 已发牌
                if (isset($oneuser['uid']) && intval($oneuser['uid']) == $loginUid) { // 显示发给我的手牌；
                    $palyUser[$sid]['cards'] = isset($cards[$sid]) ? $cards[$sid] : [];
                }
            }
        } // 拼牌完成 摊牌 ===> 结算数据（显示玩家最后的结算数据）
        else if (in_array($gameStatus, [
            CardEnum::GAME_STEP_4,
            CardEnum::GAME_STEP_5
        ], true)) {
            $cards = BaseComm::distMemoryCards($gameNo,FALSE); // 全局变量获取手牌数据（座位号seatNo=> [11,23,233]）
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = "结算中";
                $palyUser[$sid]['ifcards'] = 1; // 已发牌
                $palyUser[$sid]['cards'] = isset($cards[$sid]) ? $cards[$sid] : [];

                // 显示结算所的金额数据；
                $palyUser[$sid]['lastmoney'] = 0.01;
            }
        }
        return $palyUser;
    }

    
    /**
     * DEAL 结算DZPK的逻辑处理
     * @param boolean $zjdata
     * @param boolean $xjdata
     * @param boolean $fjdata
     * @param boolean $returndata
     */
    public static function dealRoomGameDZPK($zjdata = false, $xjdata = false, $fjdata = false, &$returndata = false)
    {
        $zjNiuLevel = 0; // 比牌操作；庄家跟每个闲家一一对比；
        $zjTotalMoney = 0; // 庄家的总钱
        $gameUtype = isset($fjdata["gpKey"]) ? $fjdata["gpKey"] : ""; // 游戏类型
        $fjmoney = isset($fjdata["everyPoints"]) ? floatval($fjdata["everyPoints"]) : 0; // 房间低注金额
        $fjmaxPeop = isset($fjdata["maxPlayer"]) ? intval($fjdata["maxPlayer"]) : 0; // 房间低注金额
        $zjcode = isset($zjdata['cards']) ? $zjdata['cards'] : false; // 庄家的牌数据；
        $zjMutle = isset($zjdata['mainMutle']) ? intval($zjdata['mainMutle']) : 1; // 庄家倍数；
        $zjSeatNo = isset($zjdata['seatNo']) ? intval($zjdata['seatNo']) : 0; // 庄家座位号；
        $zjUserId = isset($zjdata['userId']) ? intval($zjdata['userId']) : 0; // 庄家UID；
        $allCards = [
            $zjSeatNo => $zjcode
        ];
        $moneyArr = [
            $zjSeatNo => array()
        ];
        $zjRes = MahjEnum::dealTwoEightLevel($zjcode, $zjNiuLevel);

        if (! empty($zjdata) && ! empty($xjdata) && sizeof($xjdata) > 0 && ! empty($zjRes) && $fjmoney > 0 && $zjSeatNo >= 0) {
            $zjCardmutl = isset($zjRes['mutl_value']) ? $zjRes['mutl_value'] : 1; // 牌型倍数
            /*
             * if (isset($zjRes['niuGroups']) && !empty($zjRes['niuGroups'])) {
             * $zjcode = BaseEnum::changeGroupArray($zjcode,$zjRes['niuGroups']) ;
             * }
             */
            $zjRes['cards'] = $zjcode;
            // echo '庄-><br>'.print_r($zjRes,true);
            foreach ($xjdata as $xjinfo) {
                $xjLevel = - 1; // 闲家牛等级
                $xjMoney = 0; // 闲家赢的钱
                $xjWater = 0; // 最后计算抽水的钱；

                $xjBets = isset($xjinfo['mainMutle']) ? intval($xjinfo['mainMutle']) : 1; // 闲家下注倍数；
                $xianjCard = isset($xjinfo['cards']) ? $xjinfo['cards'] : false;
                $xjSeatNo = isset($xjinfo['seatNo']) ? intval($xjinfo['seatNo']) : 0; // 庄家座位号；
                $xjUserId = isset($xjinfo['userId']) ? intval($xjinfo['userId']) : 0; // 庄家座位号；
                $allCards[$xjSeatNo] = $xianjCard;

                $xjRes = MahjEnum::dealTwoEightLevel($xianjCard, $xjLevel);
                $lastWin = 1; // 通过计算谁家赢：1-庄赢，2-闲赢,
                if (! empty($xianjCard) && ! empty($xjRes) && $xjLevel >= 0 && $xjSeatNo >= 0) {
                    $xjCardMut = isset($xjRes['mutl_value']) ? $xjRes['mutl_value'] : 1; // 牌型倍数
                    /*
                     * if (isset($xjRes['niuGroups']) && !empty($xjRes['niuGroups'])) {
                     * $xianjCard = BaseEnum::changeGroupArray($xianjCard,$xjRes['niuGroups']) ;
                     * }
                     */
                    $xjRes['cards'] = $xianjCard;
                    // echo "闲->{$xjSeatNo}<br>".print_r($xjRes,true);
                    // 比大小：第一步，比KEY值；
                    if ($zjNiuLevel > $xjLevel) { // 牛相比； 庄赢；
                        $lastWin = 1;
                    } else if ($zjNiuLevel < $xjLevel) { // 牛相比； 闲赢；
                        $lastWin = 2;
                    } else if ($zjNiuLevel == $xjLevel) { // 牛相同，比其它； 点数；
                                                          // 牛牛相同时：比较大小；闲赢还是庄赢；
                        $lastWin = self::gatherWhoWin($zjRes, $xjRes, $xjLevel);
                    }
                    // 计算输赢的钱数据；
                    $zjMoney = self::countWinMoney($lastWin, $fjmoney, $zjMutle, $zjCardmutl, $xjBets, $xjCardMut, $xjMoney);
                    $zjTotalMoney = bcadd($zjTotalMoney, $zjMoney, 2);
                    // var_dump("庄家赢的钱： ".$zjMoney . " 总共： ". $zjTotalMoney);
                    $xjBetMoney = abs($xjMoney); // 玩家的下注的钱:玩家赢的钱，和输的钱：只有正数；
                    $moneyArr[$xjSeatNo] = array(
                        "uid" => $xjUserId,
                        "seatNo" => $xjSeatNo,
                        "money" => floatval($xjMoney),
                        "eachprice" => $xjBetMoney,
                        "level" => $xjLevel,
                        "card_mutle" => $xjCardMut,
                        "zj" => '闲',
                        "cards" => $xianjCard
                    );
                }
            }

            // 闲家信息没有问题；
            if (! empty($moneyArr) && sizeof($moneyArr) >= 1) {
                $moneyArr[$zjSeatNo] = array(
                    "uid" => $zjUserId,
                    "seatNo" => $zjSeatNo,
                    "money" => floatval($zjTotalMoney),
                    "eachprice" => abs($zjTotalMoney),
                    "level" => $zjNiuLevel,
                    "card_mutle" => $zjCardmutl,
                    "bet" => '庄',
                    "cards" => $zjcode
                );
                // 合计起来，再处理特殊情况 ：庄家钱不赔线的情况；
                // foreach ($moneyArr as $r => $onemony) {}
                // 所有玩家有赢钱就抽掉水money=0保本; 不抽
                foreach ($moneyArr as $sit => $onemom) {
                    $zjWater = 0;
                    if ((isset($onemom["money"]) && floatval($onemom["money"]) > 0)) {
                        $zjWater = bcmul($onemom["money"], BaseComm::getSetWaterDott(), 2); // 最后计算抽水的钱；
                    }
                    $moneyArr[$sit]["water"] = floatval($zjWater); // 抽水；
                }
                // 手牌信息组合；包含信息：总共多少位置，每个玩家的手牌，庄家位置信息；
                $cardValue = BaseComm::conectUserCardsValue($gameUtype, $fjmaxPeop, $allCards, $zjSeatNo);
                $returndata["cardvalues"] = ! empty($cardValue) ? $cardValue : ""; // 手牌组合数据
            }
        }
        return $moneyArr;
    }
    
    /**
     *  TODO TWO 第二轮操作处理
     *  TODO 摊牌和比牌（Showdown）
     *   1   四轮下注都完成后，若还剩余两名或两名以上玩家，则进行比牌。比牌时，每位玩家用手中的两张底牌与五张公共牌中选出五张组成最大的牌型进行比较大小。如使用的五张全是公共牌，两张底牌不列入比较范围，各玩家只能平分底池。
     *   2   比牌后，牌型最大的玩家赢得底池所有筹码；若多位玩家牌型相同，则平分底池。
     *   PS：中途若有玩家弃牌并只剩一名玩家，则牌局提前结束，奖池归剩下的该名玩家所有。
     *
     *   TODO 比牌规则
     *   TO 成手牌比牌时不分花色，从大到小比牌（如：都有一对的，对子大的胜出；对子相同，则比单张更大的胜出。以此类推）。若依次比牌完毕，双方大小相同，则均分底池内的注码。
     *   TODO 奖池分配
     *   TO 当牌局只剩下一名玩家手上有牌，其它玩家均弃牌时，则直接由该玩家赢得奖池中的所有筹码。
     *   TO 若有2名或以上的玩家参与比牌，则由牌型大者赢得该参与的奖池，若牌型相同则平分该奖池。
     *   @param $getNextUserSeatId int 下一位玩家的seatNo值
     */
    protected function NextSecondGame($gameRId,$gameNo,$getNextUserSeatId = 0 ,$gameLun = 2){
        $lastUsers = [];    //所有最后剩余的玩家列表
        
        $fjDetali = BaseComm::distMemoryRooms($gameNo,FALSE);
        $cardList = BaseComm::distMemoryCards($gameNo);
        $userplays = isset($fjDetali['lists']) ? $fjDetali['lists'] : FALSE;
        $fjStatus = isset($fjDetali['fjStatus']) ? $fjDetali['fjStatus'] : 0;
        $lastSiteNo = $getNextUserSeatId;                                  //当前轮开始位置
        BaseEnum::Logger("第{$gameLun}轮发公共牌：(NextSecondGame)->  下一位玩家[siteNo={$lastSiteNo}]", 'user-login');           // 所有玩家FD
        BaseEnum::Logger("取出公共牌：(NextSecondGame)->  [NO={$gameNo}]  cards=".json_encode($cardList), 'user-login');          // 所有牌
        $publicCards = isset($cardList['common']) ? $cardList['common'] : FALSE;            //取出公共牌；
        if(empty($publicCards) || !is_array($publicCards) || sizeof($publicCards) != 5 || !$userplays){
            BaseEnum::Logger("公共牌出错：(NextSecondGame)->  [NO={$gameNo}]  IS ERROR!!! ->".json_encode($publicCards), 'user-login');        // 所有牌
            return FALSE;
        }
        $allFds = array_column($userplays, 'fd','seatNo');
        //TODO 第二轮发公共牌：
        $firstCards = array_slice($publicCards,0,3); //前三张；
        $seconCards = array_slice($publicCards,3,1); //第四张
        $lastCards  = array_slice($publicCards,4,1); //第五张
        $AllpublicCards = $firstCards;               //公共牌总数
        
        //TODO 公共牌都发完，直接比所有牌型； 
        if($gameLun > 4){
            BaseEnum::Logger("所有轮结束，直接比牌：PlayDZPoker-(NextSecondGame)-> 并结算处理 !!! =>" . json_encode($publicCards), 'user-login'); // 所有玩家FD
            $fjDetail = BaseComm::distMemoryRooms($gameNo,FALSE);
            $userPlays = $fjDetail['lists'] ?? FALSE;
            $userMaxCas = $fjDetail['maxUserCards'] ?? FALSE;
            $userBets = array_column($userPlays, "total_money", "uid");         //总下注
            $deskAll = isset($fjDetail["deskMoney"]) ? floatval($fjDetail["deskMoney"]) : 0;
            BaseEnum::Logger("内存数据 =>" . json_encode($fjDetail), 'user-login'); // 所有玩家FD
            
            $userDealRes = [];  //结算列表
            $notGiveupIds = []; //未弃牌玩家ID
            if (!empty($userPlays)) {
                foreach ($userPlays as $onew){
                    $byuid = $onew['uid'] ?? 0;         //取出最后还没弃牌的玩家主动比牌
                    $byseatno = $onew['seatNo'] ?? 0;   //座位号
                    $oneHand = isset($onew['play_hand']) ? intval($onew['play_hand']) : -1 ;
                    $totalMoney = isset($onew['total_money']) ? floatval($onew['total_money']) :0 ; //玩家自己下注金额；
                    
                    //TODO 结算已弃牌的玩家
                    if($oneHand === CardEnum::DZPK_TYPE_0){                                         //弃牌就是默认下注的人的钱都是输掉的
                        $xjMoney = 0 - $totalMoney;
                        $xjBetMoney = ($xjMoney < 0) ? abs($xjMoney) : 0;
                        $userDealRes[$byseatno] = [
                            "uid" => $byuid,
                            "seatNo" => $byseatno,
                            "money"  => floatval($xjMoney),         //盈亏值
                            "eachprice" => floatval($xjBetMoney),   //有效下注(正数)
                            "level"  => 0 ,
                            "water"  =>   0,
                            "card_mutle" => 1,
                        ];
                    }else if($byuid > 0){
                        array_push($notGiveupIds, $byuid);
                        $oneDel = $userMaxCas[$byseatno] ?? FALSE;  //TODO 剩余玩家
                        $cardLevel = $oneDel['level'] ?? 0;
                        $cardString = $oneDel['cards'] ?? FALSE;    //取牌数据字段
                        $lastUsers[] = ["seatNo"=> $onew['seatNo'] ?? 0,"uid"=> intval($byuid), "maxCards" => $cardString,"cardLevel"=>$cardLevel,"pLevel"=> $oneDel['pLevel'] ?? ""] ;
                    }
                }
            }
            
            BaseEnum::Logger("已弃牌玩家：=>" . json_encode($userDealRes), 'user-login'); // 所有玩家FD
            //TODO 剩余玩家开始拿最大的牌来进行对比（人数要>=2）
            if(!empty($lastUsers) && sizeof($lastUsers) >= 2){
                $deskEvery = $deskAll ;
                //发送比牌操作
                BaseEnum::Logger("最后比牌的玩家 =>" . json_encode($lastUsers), 'user-login'); // 所有玩家FD
                $maxPlevInfo = $allLevNums = FALSE;
                //TODO 按大到小的排列出来未弃牌的玩家等级
                $lastRes = PorkerEnum::playCombSize($lastUsers,$allLevNums,$maxPlevInfo);
                BaseEnum::Logger("玩家大小排序 =>" . json_encode($lastRes), 'user-login'); // 所有玩家FD
                if(!$lastRes || !$allLevNums) return FALSE;
                $pLevNum = $maxPlevInfo['num'] ?? 0;
                $pLevVal = $maxPlevInfo['pLevel'] ?? "";
                BaseEnum::Logger("牌的等级排序 =>最高牌人数统计：Level={$pLevVal}共{$pLevNum}个, 统计每个牌的数量=> " . json_encode($allLevNums), 'user-login'); // 所有玩家FD
                
                //TODO  考虑多种情况,1、没有 All IN  只有玩家的池底金额（暂无边池的情况下）
                if(TRUE){
                    if ($pLevNum > 1) { 
                        $deskEvery = $deskEvery/$pLevNum;   //多个玩家的牌值相同则要平分奖池
                    }
                    //TODO  出现的情况只有一方(或相等，平分奖池------按大到小的排列出来未弃牌的玩家等级)
                    foreach ($lastRes as $onepplay) {
                        $water2 = 0;
                        $byuid2 = $onepplay['uid'] ?? 0;         //取出最后还没弃牌的玩家主动比牌
                        $byseatno2 = $onepplay['seatNo'] ?? 0;   //座位号
                        $xjMoney = $userBets[$byuid2] ?? 0 ;     //下注的钱
                        $xjBetMoney = $xjMoney;
                        if(isset($onepplay['pLevel']) && $onepplay['pLevel'] != $pLevVal){  //玩家比失败;扣钱
                            $xjMoney = 0 - $xjMoney;            //下注的钱
                            $xjBetMoney = abs($xjMoney);
                        }else{ 
                            //TODO 赢钱的玩家(平分桌面上所有下注= deskAll/N - 下注 ＝输赢)
                            $xjMoney = bcsub($deskEvery,$xjMoney ,3);                           //第一个玩家赢的玩家拿走所有桌面上的钱
                            $water2 = bcmul(BaseComm::getSetWaterDott(), $xjMoney ,3) ;         //抽水的钱
                            $xjBetMoney = bcsub($xjMoney , $water2 , 3) ;                       //有效下注
                        }
                        //TODO 后面的玩家输赢计算
                        $userDealRes[$byseatno2] = [
                            "uid" => $byuid2,
                            "seatNo" => $byseatno2,
                            "money"  => floatval($xjMoney),         //盈亏值
                            "eachprice" => floatval($xjBetMoney),   //有效下注(正数)
                            "level"  => $onepplay['cardLevel'] ?? 0,
                            "pLevel"  => $onepplay['pLevel'] ?? "", //最后的结算值
                            "water"  =>   $water2,
                            "card_mutle" => 1 ,
                        ];
                    }
                    BaseEnum::Logger("玩家输赢结算成功->等待入库：DealResult =>" . json_encode($userDealRes), 'user-login'); // 所有玩家FD
                }else{
                    
                    
                }
                //结算订单操作
                $this -> dealGameUserOrder($gameRId,$gameNo,$userDealRes,$userPlays,$notGiveupIds);
                return FALSE;
            }else{
                BaseEnum::Logger("第{$gameLun}轮结束后停掉结算异常：结算失败！！！！] ； Res-->".json_encode($lastUsers)." 玩家数据-=" . json_encode($userPlays), 'user-login'); // 所有玩家FD
            }
            return FALSE ;
        }
        //TODO 保存当前游戏的轮数
        $fjDetali['playTimes'] = $gameLun; 
        BaseComm::distMemoryRooms($gameNo,TRUE,$fjDetali);          
        
        $stepNum = $gameLun - 1; //步骤少一轮
        $pushData = ["step" => $stepNum,"cards"=>$firstCards,'room_status' => $fjStatus];
        if($stepNum === 2){
            $pushData["cards"] = $seconCards;
            $AllpublicCards = array_merge($firstCards,$seconCards);
        }else if($stepNum===3){
            $pushData["cards"] = $lastCards;
            $AllpublicCards = $publicCards; 
        }
        $pushCardInfo = ['m'=>BaseEnum::XYM_0X62,"data"=>$pushData];
        AuthCommon::pushFrontWeb($allFds,json_encode($pushCardInfo));                       //前三张公共牌
        
        
        //每个玩家最大的手牌值
        $maxCardsList = [];
        
        //计算每个玩家最高的手牌数据并推送级每位玩家的牌型数据
        foreach ($allFds as $seatins => $oneFd){
            $oneCard = isset($cardList[$seatins]) ? $cardList[$seatins] : FALSE;            //获取手牌数据
            $maxCname = FALSE;
            if (isset($oneCard) && !empty($oneCard)) {                                      //计算最高手牌
                $conBackCards = array_merge($AllpublicCards,$oneCard);
                
                //TODO 计算新号码组成后第一手牌（最大的手牌）
                $maxCars = PorkerEnum::getPlayMaxCards($conBackCards, 5 ,$maxCname);        //取最大手牌数据
                $curLevl = isset($maxCname['level']) ? intval($maxCname['level']) : 0;
                $maxCname["seatNo"] = $seatins;
                $pushLS = ["seatNo" =>$seatins ,"step" => $stepNum,"cards" => $maxCars,"level"=> $curLevl,'detail' => $maxCname];
                BaseEnum::Logger("第{$gameLun}轮计算玩家手牌组合：PUSH 玩家[siteNo={$seatins}] LEVEL =[ {$curLevl} 等级]-->".json_encode($conBackCards)." Res=" . json_encode($pushLS), 'user-login'); // 所有玩家FD
                $pushCardInfo = ['m'=>BaseEnum::XYM_0X64,"data"=>$pushLS];
                AuthCommon::pushFrontWeb($oneFd,json_encode($pushCardInfo));                //与公共牌组成的最大手牌数据；
                $maxCardsList[$seatins] =  $maxCname;                                       //每个玩家位置的最大牌
            }
        }
        if(!empty($maxCardsList)){
            $fjInfo2 = BaseComm::distMemoryRooms($gameNo,FALSE);
            $fjInfo2["maxUserCards"] = $maxCardsList;
            BaseComm::distMemoryRooms($gameNo,TRUE,$fjInfo2);                               //最大的数据存起来["level": 1, "name": "高牌", "cards": "5,49,59,29,36"]
        }
        
        //TODO 第二轮表态：发完公共牌，每个玩家跟注或者加注
        BaseEnum::Logger("第{$gameLun}轮表态==>开始：PlayDZPoker-(NextSecondGame)->  从玩家[siteNo={$lastSiteNo}]开始---->>>" . json_encode($allFds), 'user-login');         // 所有玩家FD
        $this -> waitPlayerHander($gameNo, $allFds,$fjStatus,$lastSiteNo,$gameLun);
    }
    
    /**
     * TODO 结算订单操作
     * TO 四轮都结束后，若还剩余两名及以上的玩家才比牌；
     * TO 比牌时，每位玩家的手中2张底牌与5张公共牌任选5张组成最大牌者进行比较大小。胜者赢得底池所有注码，若有多人获取胜，平分底池注码.
     * @param int $gameRId
     * @param string $gameNo
     * @param array $dealRes
     * @return number
     */
    protected function dealGameUserOrder($gameRId,$gameNo,$dealRes,$players = FALSE,$notGiveupIds = FALSE) {
        $gameModel = new GameType();
        //结果出来后，要操作对应的用户身份上；
        $tbDisplayName = 'qc_game_display';
        //测试数据
        $returndata = ['cardvalues' =>  '23434234;2343434234'] ;
        $cardValue = isset($returndata['cardvalues']) ? $returndata ['cardvalues'] :"";
        $model = new GameType();            //写一行数据；
        //去取玩家要下注的房间信息
        $fanjianInfo = $model -> getGameTableDetail($gameNo); 
        $gameDetail = BaseComm::distMemoryRooms($gameNo,FALSE);
        $gameId = $gameDetail['gameId'] ?? 0;
        $playsEss = $gameDetail['lists'] ?? FALSE;
        $maxUserCards = $gameDetail['maxUserCards'] ?? FALSE;
        if(!empty($playsEss) && !empty($dealRes) && !empty($returndata) && !empty($cardValue) && !empty($gameDetail) && $gameId > 0 ) {
            //把玩家的订单信息补全；
            $userIds = array_column($playsEss, "uid","seatNo");
            $userFds = array_column($playsEss, "fd","seatNo");
            
            //组状下注信息；（闲家下注）
            $editData = ["mainMutl" => 1 ]; //抢的倍数
            $editData["mainUid"] = isset($userIds[0]) ? intval($userIds[0]) : 0 ;
            $playOrder = GameCommon::createUserOrderFrom(implode(',', $userIds) , $fanjianInfo, $editData,false,$players);     //玩家订单信息
            
            if(!empty($playOrder)){
                $gameModel->dbConnector() -> insertMulti("qc_games_orders", $playOrder) ;
            }else{
                BaseEnum::Logger('订单出错：(dealGameUserOrder---Error)===-->' . json_encode($playOrder), 'user-login');
                return FALSE;
            }
            
            //桌子信息==> 更新用户的输赢信息；
            $errorCode = -1;
            
            //结算订单数据；
            //操作相关的注单信息；1、修改订单状态，补全订单信息； 2、用户资金交易数据处理； 3、收拾桌面数据，匹配列表清空；
            $result = GameCommon::dealUserOrder($gameRId,$gameNo,$dealRes,$returndata,$errorCode);
            BaseEnum::Logger('输出结果：(Result)=>' . json_encode($result), 'user-login');
            
            $playCards = BaseComm::distMemoryCards($gameNo,FALSE);
            BaseEnum::Logger('玩家所有手牌：(playCards)=>' . json_encode($playCards), 'user-login');
            
            //操作数据 ＝＝＝＝ 组装成 WEB端要用的数据；
            if(!empty($result) && sizeof($result) > 0){ //结算成功；
                foreach ($dealRes as $r => $dealobj){
                    $cardLev = -1;
                    $cardName = '';
                    $oneuid = isset($dealobj['uid']) ? intval($dealobj['uid']):0 ;
                    $oneSid = isset($dealobj['seatNo']) ? intval($dealobj['seatNo']):0 ;
                    $ucards = (isset($playCards[$oneSid]) && !empty($playCards[$oneSid])) ? $playCards[$oneSid] : [];
                    $oneArr = isset($result[$oneuid]) ? $result[$oneuid]:FALSE ;
                    $useChangeFee = isset($oneArr['changeMoney']) ? floatval($oneArr['changeMoney']) :0 ;
                    if(!empty($oneArr) && isset($oneArr['points'])){
                        $dealRes[$r]["points"] = floatval($oneArr['points']);
                        $dealRes[$r]["changeMoney"] = $useChangeFee;
                        $dealRes[$r]["cards"] = (!empty($notGiveupIds) && in_array($oneuid, $notGiveupIds) ) ? $ucards : [];    // 玩家手里牌(只有未弃牌的玩家才会显示手牌)
                        $dealRes[$r]["maxCards"] = [];  
                        if(!empty($notGiveupIds) && in_array($oneuid, $notGiveupIds)){
                            $getCa = $maxUserCards[$r] ?? FALSE;
                            $cardLev = $getCa['level'] ?? 0;
                            $cardName = $getCa['name'] ?? "";
                            $cardval = (isset($getCa['cards']) && !empty($getCa['cards']))  ? explode(',', $getCa['cards']) : []; //最大牌值
                            $dealRes[$r]["maxCards"] = $cardval;    //TODO 玩家手中与桌面组成的最大牌型数据
                        }
                        $dealRes[$r]["level"] = $cardLev;
                        $dealRes[$r]["maxCardsName"] = $cardName;
                    }
                }
                //把牌局信息补全；
                $editDisplay = ["playerInfo"=> json_encode($dealRes,JSON_FORCE_OBJECT),"finishDateTime"=> BaseEnum::getNowTime(true),"openStatus" => 2];
                $whertOpt = ["roomId"=>$gameRId,"gameNo"=> $gameNo];
                
                $reds = DBTools::PoolUpdate($tbDisplayName,$editDisplay,$whertOpt);
                
                //TODO 数据成功 推送：所有牌数据和输赢
                if(isset($reds) && intval($reds) > 0 && !empty($dealRes)){
                    $gameDoRealNum = sizeof($gameDetail['lists']);  //真实人数统计
                    BaseEnum::Logger("结算完成：(dealPlayMoney玩家数：{$gameDoRealNum}位)===[SUCCESS] 补全牌局信息--> res:".$reds. "==== " . json_encode($editDisplay), 'user-login');
                    
                    $gameDetail['fjStatus'] = CardEnum::GAME_STEP_5;
                    if (isset($gameDetail['lists']) && ! empty($gameDetail['lists'])) {
                        foreach ($gameDetail['lists'] as $setiid => $fg) {
                            $gameDetail['lists'][$setiid]["pstatus"] = CardEnum::GAME_STEP_5;
                        }
                    }
                    BaseComm::distMemoryRooms($gameNo, TRUE, $gameDetail); // 保存用户数据
                    
                    //TODO 前端结算
                    $pushArray = ['m' => BaseEnum::XYM_0X1C,"data" => $dealRes];
                    AuthCommon::pushFrontWeb($userFds, json_encode($pushArray));
                    
                    //TODO 在线玩家数据（游戏结束，在线人数减少）
                    BaseComm::changeOnLines($gameId,$gameDoRealNum,1);
                    BaseComm::distLastGameNoListRedis($userIds,TRUE,FALSE); //清掉最新局
                    return TRUE;
                } else {
                    BaseEnum::Logger('牛牛结算处理：结算失败 ！！！！PlayNiuNiu-(asycWaitDealCenter)-；======>  ' . print_r($dealRes, true), 'user-login');
                    return false;
                }
                return TRUE;     //数据处理成功；返回内容；
            }
        }
    }
    
    
    /**
     * TODO 比较大小；闲赢还是庄赢 
     * @param array $zjRes 庄
     * @param boolean $xjInfo闲
     * @return boolean
     */
    private static function gatherWhoWin($zjRes, $xjInfo = false, $zjNiuLevel = false) {
        $lastWin = 1;       // 比谁的最大点数大；
        if (isset($zjRes["maxCardKey"]) && intval($zjRes["maxCardKey"]) > 0 && isset($xjInfo["maxCardKey"]) && intval($xjInfo["maxCardKey"])) {
            if (intval($zjRes["maxCardKey"]) < intval($xjInfo["maxCardKey"])) { // 当两个点数相同也是庄家赢
                $lastWin = 2;
            }
        } else { 
            $zjCard = isset($zjRes["cards"]) ? $zjRes["cards"] : FALSE;         // 比相同点数时的数据：
            $xjCard = isset($xjInfo["cards"]) ? $xjInfo["cards"] : FALSE;       // 比牌值
            if (! empty($zjCard) && ! empty($xjCard) && max($zjCard) < max($xjCard)) { // 取最的大牌值；
                $lastWin = 2;   // 完全一样的牌都是庄家赢；
            }
        }
        return $lastWin;
    }

    /**
     * TODO 计算庄输赢数据（不考虑赢家抽水的情况）
     * @param  bool 庄家赢为True
     */
    private static function countWinMoney($mainwin = 1, $fjmoney = 0, $zjMutle = 0, $zjCardmutl = 1, $xjBets = 1, $xjCardMut = 1, & $xianMoney = 0)
    {
        // 庄赢 ：庄家胜利所赢 ＝ 闲家下注倍数*房间底注 －抽水 | 闲家失败所输 ＝ 闲家下注倍数*房间底注
        $mainMoney = 0;
        if (intval($mainwin) === 1) {
            $tempMon = $fjmoney * $xjBets; // * $zjMutle * $xjBets ; //A*M*X*Y
            $mainMoney = bcsub($tempMon, 0, 2); // 庄家赢的
            $xianMoney = bcsub(0, $tempMon, 2); // 闲家输的
        } else {
            // 庄输；庄家失败所输 ＝ A*N*X*Y | 闲家胜利所赢 ＝ A*N*X*Y －抽水
            $tempMon = $fjmoney * $xjBets; // $xjCardMut * $zjMutle
            $mainMoney = bcsub(0, $tempMon, 2); // 闲家赢的
            $xianMoney = bcsub($tempMon, 0, 2); // 庄家输的
        }
        return $mainMoney;
    }
     
}

?>